package com.yvan.metrics;

import com.codahale.metrics.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.management.ManagementFactory;

/**
 * 实时监控类库,用于统计后台调用的过滤器
 * Created by luoyifan on 2017/5/5.
 */
@Configuration
public class MetricAutoConfiguration {
    private static final Logger LOGGER = LoggerFactory.getLogger(MetricAutoConfiguration.class);
    private static final String PID = ManagementFactory.getRuntimeMXBean().getName();

    @Bean
    public MetricRegistry metrics() {
        return new MetricRegistry();
    }

    /**
     * 并发量计算
     */
    @Bean(name = "metricsConcurrency")
    public Counter metricsConcurrency(MetricRegistry metrics) {
        Counter r = metrics.counter("concurrency");
        r.inc();
        return r;
    }

    /**
     * TPS 计算器
     */
    @Bean(name = "metricsRequest")
    public Meter metricsRequest(MetricRegistry metrics) {
        return metrics.meter("request");
    }

    /**
     * 请求大小
     */
    @Bean(name = "metricsResponseSizes")
    public Histogram metricsResponseSizes(MetricRegistry metrics) {
        return metrics.histogram("response-sizes");
    }

    /**
     * 请求数
     */
    @Bean(name = "metricsRequestCount")
    public Counter metricsRequestCount(MetricRegistry metrics) {
        return metrics.counter("requestCount");
    }

    /**
     * db-tps 计数
     */
    @Bean(name = "jdbc")
    public Meter jdbc(MetricRegistry metrics) {
        return metrics.meter("jdbc");
    }

    @Bean(name = "jdbcConcurrency")
    public Counter jdbcConcurrency(MetricRegistry metrics) {
        return metrics.counter("jdbcConcurrency");
    }

    /**
     * db 请求数
     */
    @Bean(name = "jdbcCount")
    public Counter jdbcCount(MetricRegistry metrics) {
        return metrics.counter("jdbcCount");
    }

    /**
     * db 延迟数
     */
    @Bean(name = "jdbcExecuteTime")
    public Timer jdbcExecuteTime(MetricRegistry metrics) {
        return metrics.timer("jdbcExecuteTime");
    }

    /**
     * 执行时间计时器
     */
    @Bean(name = "metricsExecuteTime")
    public Timer metricsExecuteTime(MetricRegistry metrics) {
        return metrics.timer("executeTime");
    }


    @Bean
    public FilterRegistrationBean filterRegistrationBean(@Qualifier("metricsRequest") final Meter metricsRequest,
                                                         @Qualifier("metricsRequestCount") final Counter metricsRequestCount,
                                                         @Qualifier("metricsExecuteTime") final Timer metricsExecuteTime,
                                                         @Qualifier("metricsConcurrency") final Counter metricsConcurrency) {

        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new Filter() {
            @Override
            public void init(FilterConfig filterConfig) throws ServletException {
                LOGGER.info("metrics inited");
            }

            @Override
            public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
                if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
                    chain.doFilter(request, response);
                    return;
                }

                HttpServletResponse httpResponse = (HttpServletResponse) response;
                HttpServletRequest httpRequest = (HttpServletRequest) request;

                metricsRequest.mark();
                metricsRequestCount.inc();
                metricsConcurrency.inc();

                final Timer.Context time = metricsExecuteTime.time();
                try {
                    ((HttpServletResponse) response).setHeader("YVAN-HOST", PID);
                    chain.doFilter(httpRequest, httpResponse);
                    //metricsResponseSizes.update(httpResponse);

                } finally {
                    metricsConcurrency.dec();
                    time.stop();
                }
            }

            @Override
            public void destroy() {

            }
        });

        //添加过滤规则.
        filterRegistrationBean.addUrlPatterns("/*");

        //添加不需要忽略的格式信息.
        return filterRegistrationBean;
    }
}
